#include "viewer.h"
#include "diamond.h"
#include "square.h"
#include "curve.h"

#include <string>
#include <iostream>

#ifdef _MAC_OS_
#include <GLUT/glut.h>
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#else
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#endif

using namespace std;

Viewer::Viewer():
  _halfSize(0.5),
  _growing(true){
  }


Viewer::~Viewer(){

}


////////////////////////////////////////////////////////////////////////////////
// GL stuff

// initialize OpenGL context
void
Viewer::init(int w, int h){
  // background color
  glClearColor (0.0, 0.0, 0.0, 1.0);

  // viewport
  glViewport (0, 0, w, h);

}

void
Viewer::reshape(int w, int h){
  glViewport (0, 0, w, h);
}


/*!
   callback to draw graphic primitives
   you may edit it if you want to change de drawing procedure (add new objects
   for example).
 */
void
Viewer::display() const{
  // clear current buffer
  glClear (GL_COLOR_BUFFER_BIT);

  // define projetion matrix
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity (); 
  glOrtho (-1.1, 1.1, -1.1, 1.1, -10, 10);

  // define model view matrix
  glMatrixMode (GL_MODELVIEW);
  glLoadIdentity ();

  /////////////////////////////////////
  // Draw the primitives.
  //
   std::vector<Shape*>::const_iterator it;
  for (it=_shapes.begin(); it<_shapes.end(); it++)
  	(*it)->draw();
  //
  // End of drawing
  /////////////////////////////////////

  glFlush();
}


void 
Viewer::updateScene () {
	if (_growing){ // grow square
		_halfSize += 0.0001;
		std::vector<Shape*>::const_iterator it;
		for (it=_shapes.begin(); it<_shapes.end(); it++){
			(*it)->setDim((*it)->getDim() + 0.0001);
		}
		_growing = _halfSize < 0.7; // grow square until _halfSize >= 0.8
	} else {
		_halfSize -= 0.0001;
		std::vector<Shape*>::const_iterator it;
		for (it=_shapes.begin(); it<_shapes.end(); it++){
			(*it)->setDim((*it)->getDim() - 0.0001);
		}
		_growing = _halfSize < 0.4;// grow square until _halfSize <= 0.3
	}
	
	std::vector<Shape*>::const_iterator it;
	for (it=_shapes.begin(); it<_shapes.end(); it++)
		(*it)->setPosition((*it)->getPos() + (*it)->getSpeed()*0.0005);
	
	
    for (it=_shapes.begin(); it<_shapes.end(); it++){
    	vec2f v = 5*(-0.5+(double) rand() / (RAND_MAX));
    	v[1] = 5*(-0.5+(double) rand() / (RAND_MAX));
	     (*it)->setSpeed(v);
    }
	
	
	display();
}


////////////////////////////////////////////////////////////////////////////////
// Events

/*!
   callback to manage mouse : called when user press or release mouse button
   You can change in this function the way the user 
   interact with the system.
 */
void  
Viewer::mousePressed(int button, int state, int x, int y){
   std::string buttonName;

   switch(button){
   case GLUT_LEFT_BUTTON:
      buttonName = string("left");
      break;
   case GLUT_MIDDLE_BUTTON:
      buttonName = string("middle");
      break;
   case GLUT_RIGHT_BUTTON:
      buttonName = string("right");
      break;
   default:
      buttonName = string("invalid");
   }

    std::vector<Shape*>::const_iterator it;
    for (it=_shapes.begin(); it<_shapes.end(); it++){
    	vec2f v = vec2f((double) (1.1*(x-300))/300.);
    	v[1] = (double) (1.1*(y-300))/300.;
	     (*it)->setSpeed(v);
    }

   cout << "User " 
        << (state == GLUT_DOWN ? "press " : "release ")
        << buttonName.c_str()
        << " button in "
        << x 
        << ", "
        << y
        << endl;

   // request display refresh
   glutPostRedisplay(); 
}


 
 
/*!
   callback to manage mouse : called when user move mouse with button pressed
   You can change in this function the way the user 
   interact with the system.
 */
void
Viewer::mouseMoved(int x, int y){
     cout << "Mouse moved in "
        << x 
        << ", "
        << y
        << endl;

   // request display refresh
   glutPostRedisplay(); 
}


/*!
   callback to manage keyboard interactions
   You can change in this function the way the user 
   interact with the system.
 */
void
Viewer::keyPressed(unsigned char key, int x, int y){
	if(key == 's' or key == 'S'){
		_shapes.push_back(new Square());
	}
	if(key == 'd' or key == 'D'){
		_shapes.push_back(new Diamond());
	}
	if(key == 'c' or key == 'C'){
		_shapes.push_back(new Curve());
	}
}
